﻿using System;
using System.Collections.Generic;
using System.Configuration;
using log4net;
using NHibernate;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
using NHibernate.Tool.hbm2ddl;

namespace KpBusiness.Layer
{
    
    public sealed class DataAccessLayerHelper
    {
        
        #region Variables
        private static readonly ILog log = LogManager.GetLogger("Layer");
        private static List<ISessionFactory> readerSessionList =   readerSessionList = new List<ISessionFactory>();
        private static ISessionFactory writerSession = null;

        private const string NUMBER_OF_READERS = "NumberOfReaders";
        private const string READER_CONNETION_STRING = "ReaderConnetionStrings";
        private const string WRITER_CONNETION_STRING = "WriterConnetionStrings";

        private static string ConfigConReaderString;
        private static string[] ConfigConWritterStringArray;


        private static int connetionNumber;
        #endregion

        private DataAccessLayerHelper()
        {}

        static DataAccessLayerHelper()
        {

            
            BuildReaderSessions();

            
        }
        /// <summary>
        /// Build Array of REaders Session objects
        /// </summary>
        /// <returns></returns>
        private static bool BuildReaderSessions()
        {
            log.Debug("Started");
            ConfigConReaderString = System.Configuration.ConfigurationManager.AppSettings[READER_CONNETION_STRING];

            ///Get Number of Readers from Config File
            int readersCnt = 0;
            try
            {
                readersCnt = int.Parse(System.Configuration.ConfigurationManager.AppSettings[NUMBER_OF_READERS], CultureInfo.CurrentCulture.NumberFormat);
            }
            catch (System.ArgumentNullException)
            {
                log.Error( "Unable to find appSettings variable NumberOfReaders in INT format or its not defined");
                throw;
            }


            /// Check if number of reader connetionstring are eual;
            ConfigConWritterStringArray = ConfigConReaderString.Split('|');

            if (ConfigConWritterStringArray.Length != readersCnt)
            {
                throw new MissingFieldException ("BuildReaderSessions","Reader Connetion String <ReaderConnetionStrings>  splitted with | sign are not eual to <NumberOfReaders> number ");
            }

            /// If number and cnt are equal create session pools
            for (int i = 0; i < readersCnt; i++)
            {
                readerSessionList.Add(getFactory(null, ConfigConWritterStringArray[i]));
            }

            log.Debug("Ended");
            return true;
        }

        /// <summary>
        /// Get Factory object
        /// System Checks if objects are created or not else it creates sessions and resturns object
        /// </summary>
        /// <param name="session">Provide Session to check if it is null and needed creation</param>
        /// <param name="ConString">Provide Connection String to create session</param>
        /// <returns></returns>
        private static ISessionFactory getFactory(ISessionFactory session, string ConString)
        {
            log.Debug("Started");
            if (session == null)
            {
                NHibernate.Cfg.Configuration config;
                config = new NHibernate.Cfg.Configuration().SetProperty("connection.connection_string", ConString);
                if (config == null)
                {
                    throw new InvalidOperationException("NHibernate configuration is null.");
                }

                config.AddAssembly("KpBusiness");
                session = config.BuildSessionFactory();


                if (session == null)
                {
                    throw new InvalidOperationException("Call to Configuration.BuildSessionFactory() returned null.");
                }
            }

            log.Debug("Ended");
            return session;

        }

        /// <summary>
        /// Open Reader Session 
        /// </summary>
        /// <returns>Return Reader Session</returns>
        public static ISession OpenReaderSession()
        {
            log.Debug("Started");

            ISession session;

            log.Debug("ConnectionNumber: " + connetionNumber);
            session = getFactory(readerSessionList[connetionNumber], ConfigConWritterStringArray[connetionNumber]).OpenSession();
            if (session == null)
            {
                throw new InvalidOperationException("Call to factory.OpenSession() returned null.");
            }

            if (connetionNumber < readerSessionList.Count - 1)
            {
                connetionNumber++;
            }
            else
            {
                connetionNumber = 0;
            }

            log.Debug("Ended");
            return session;
        }

        /// <summary>
        /// Open writer Session
        /// </summary>
        /// <returns>Return writer Session</returns>
        public static ISession OpenWriterSession()
        {
            log.Debug("Started");
            ISession session;
            session = getFactory(writerSession, ConfigurationManager.AppSettings[WRITER_CONNETION_STRING]).OpenSession();
            if (session == null)
            {
                throw new InvalidOperationException("Call to factory.OpenSession() returned null.");
            }
            log.Debug("Ended");

            return session;
        }

        /// <summary>
        /// Creates DB Schema
        /// </summary>
        public static void GenerateSchema()
        {
            NHibernate.Cfg.Configuration  config = new NHibernate.Cfg.Configuration().SetProperty("connection.connection_string", ConfigConWritterStringArray[connetionNumber]);
            if (config == null)
            {
                throw new InvalidOperationException("NHibernate configuration is null.");
            }


            config.AddAssembly("KpBusiness");

                new SchemaExport(config).Execute(false, true, false);
            //return config.GenerateSchemaCreationScript(NHibernate.Dialect.MySQL5Dialect.GetDialect());

        }

    }

}
